package com.example.exam;

import java.util.ArrayList;
import java.util.List;

/**
 * 这题是工银亚洲的笔试题
 *
 *
 * 张三和李四工作日中午去面馆吃面，面馆的价格如下：
 * 大碗中碗小碗牛肉面分别18元16元14元，
 * 大碗中碗小碗肥肠面分别20元18元16元，
 * 牛肉饼10元，
 * 奶茶12元，
 * 套餐1是38元（1大碗牛肉面+1个牛肉饼+1杯奶茶），
 * 套餐2是40元（1大碗肥肠面+1个牛肉饼+1杯奶茶） ，
 * 张三吃了套餐1+1个牛肉饼，
 * 李四吃了一碗中碗的肥肠面+2杯奶茶（面馆工作日不打折，节假日会有的活动），
 * 请用使用java实现张三和李四分别要向面馆付款多少钱的代码逻辑。
 */

// 为了实现一个可以计算任意食物组合价格的系统，并且使用设计模式，我们可以使用**策略模式（Strategy Pattern）和建造者模式（Builder Pattern）**来设计这段代码。
// 策略模式允许我们定义一系列算法，将它们封装起来，并且使它们可以互换。策略也可以理解为算法，就是算牛肉面价钱的算法就是case when写定的那些、算肥肠面的算法、算不同套餐的算法，都封装在不同策略实现类里面。
// 建造者模式可以帮助我们更灵活地创建订单。
// 通过这种方式，我们可以实现任意食品组合的价格计算，并且代码结构清晰、扩展性强。

// 定义一个接口表示食品项
// 食品项和价格: 定义了多个实现Item接口的类，用于表示不同种类和规格的食品。
interface Item {
    String getName();
    double getPrice();
}

// 定义具体的食品项类
class BeefNoodle implements Item {
    private String size;

    public BeefNoodle(String size) {
        this.size = size;
    }

    @Override
    public String getName() {
        return size + " Beef Noodle";
    }

    @Override
    public double getPrice() {
        switch (size) {
            case "Large": return 18;
            case "Medium": return 16;
            case "Small": return 14;
            default: throw new IllegalArgumentException("Invalid size");
        }
    }
}

class IntestineNoodle implements Item {
    private String size;

    public IntestineNoodle(String size) {
        this.size = size;
    }

    @Override
    public String getName() {
        return size + " Pork Intestine Noodle";
    }

    @Override
    public double getPrice() {
        switch (size) {
            case "Large": return 20;
            case "Medium": return 18;
            case "Small": return 16;
            default: throw new IllegalArgumentException("Invalid size");
        }
    }
}

class BeefPie implements Item {
    @Override
    public String getName() {
        return "Beef Pie";
    }

    @Override
    public double getPrice() {
        return 10;
    }
}

class MilkTea implements Item {
    @Override
    public String getName() {
        return "Milk Tea";
    }

    @Override
    public double getPrice() {
        return 12;
    }
}

class Combo1 implements Item {
    @Override
    public String getName() {
        return "Combo 1";
    }

    @Override
    public double getPrice() {
        return 38;
    }
}

class Combo2 implements Item {
    @Override
    public String getName() {
        return "Combo 2";
    }

    @Override
    public double getPrice() {
        return 40;
    }
}


// 订单类: 使用Order类表示一个订单，包含多个食品项，并提供计算总价格和展示订单内容的方法。使用OrderBuilder类来灵活构建订单。
class Order {

    // 空容器而已。因为订单包含多个部分吗，所以要用这个空容器来装。具体参考建造者模式那个例子BuilderPatternExample中的part1、part2
    private List<Item> items = new ArrayList<>();

    // 增加分部进容器
    public void addItem(Item item) {
        items.add(item);
    }

    // 展示容器里面的所有分部
    public void showItems() {
        for (Item item : items) {
            System.out.println(item.getName() + ": " + item.getPrice() + "元");
        }
    }

    // 获取到不同分部的总价格。类比建造者模式那个例子BuilderPatternExampleConcreteBuilder中的getResult方法
    public double getTotalPrice() {
        double total = 0;
        for (Item item : items) {
            total += item.getPrice();
        }
        return total;
    }


}


// Order的构建者。
class OrderBuilder {
    // Order单个对象里面内部本来就有一个对象来装不同的订单分部List<Item> items
    private Order order;

    // 构造函数
    public OrderBuilder() {
        order = new Order(); // new OrderBuilder的时候并没有传一个Order进来，而是上面自己private Order order这样声明了一个，到时候它会自己初始话的。
    }

    public OrderBuilder addItem(Item item) {
        order.addItem(item);
        return this;
    }

    public Order build() {
        return order;
    }
}


// 使用策略模式计算订单
// 我们可以为每个顾客创建订单，并使用建造者模式构建订单内容，然后计算总价格：
// 主程序: 创建订单，添加食品项，然后计算和显示每个订单的总价格。
public class NoodleShop {
    public static void main(String[] args) {
        // 创建张三的订单
        OrderBuilder zhangSanOrderBuilder = new OrderBuilder();
        // 以下其实相当于BuilderPatternExample这个例子中，Director类中的一些逻辑。
        // 那个例子中，之所以搞个Direction，是因为分部是固定包括part1和part2，但是呢，我们这里这个例子，套餐不确定一定包含多少分部啊，所以就在下面灵活组合，不弄一个Direction写定。
        Order zhangSanOrder = zhangSanOrderBuilder
                .addItem(new Combo1())
                .addItem(new BeefPie())
                .build();

        System.out.println("张三的订单：");
        zhangSanOrder.showItems();
        System.out.println("张三需要付款: " + zhangSanOrder.getTotalPrice() + "元\n");

        // 创建李四的订单
        OrderBuilder liSiOrderBuilder = new OrderBuilder();
        Order liSiOrder = liSiOrderBuilder
                .addItem(new IntestineNoodle("Medium"))
                .addItem(new MilkTea())
                .addItem(new MilkTea())
                .build();

        System.out.println("李四的订单：");
        liSiOrder.showItems();
        System.out.println("李四需要付款: " + liSiOrder.getTotalPrice() + "元");
    }
}

